#include <stdlib.h>

#include "../hle.h"
#include "../cpu/int.h"

#include "../fs/fs.h"
#include "../fs/metafs.h"
#include "../loaders.h"

#include "../core.h"

#include "__sceAudio.h"
#include "__IoFileMgrForUser.h"
#include "__ThreadManForUser.h"
#include "__SysMemUserForUser.h"

#include "__Kernel.h"

s32 kernelRunning = 0;

void __KernelInit()
{
    if (kernelRunning)
        __KernelShutdown();

    kop_init();

    __KernelMemoryInit();
    __KernelThreadingInit();
    __IoInit();
#ifdef NO_THREAD
    __AudioInit();
#endif
    kernelRunning = 1;
}

void __KernelShutdown()
{
    _log(INF, HLE, "Shutting down kernel - %d kernel objects alive", kop_getCount());
    kernelRunning = 0;

#ifdef NO_THREAD
    __AudioShutdown();
#endif
    __IoShutdown();
    __KernelThreadingShutdown();
    __KernelMemoryShutdown();
    kop_clear();
}

KernelObjectPool kernelObjects;

void kop_init()
{
    s32 i;
    for (i = 0; i < MAXCOUNT; i++)
        kernelObjects.pool[i].occupied = 0;
}

s32 kop_getCount()
{
    s32 count = 0;
    s32 i;
    for (i = 0; i < MAXCOUNT; i++)
        if (kernelObjects.pool[i].occupied)
            count++;
    return count;
}

void *ko_get(SceUID handle)
{
    if (handle < HANDLEOFFSET || handle >= HANDLEOFFSET + MAXCOUNT
        || !kernelObjects.pool[handle - HANDLEOFFSET].occupied) {
        _log(ERR, HLE, "Kernel: Bad object handle %d", handle);
        return NULL;
    }
    else
        return kernelObjects.pool[handle - HANDLEOFFSET].ptr;
}

void *ko_search(SceUID handle, KoType type)
{
    if (!(handle < HANDLEOFFSET || handle >= HANDLEOFFSET + MAXCOUNT || !kernelObjects.pool[handle - HANDLEOFFSET].occupied))
    {
        void *t = kernelObjects.pool[handle - HANDLEOFFSET].ptr;
        if (t && kernelObjects.pool[handle - HANDLEOFFSET].type == type)
            return t;
    }
    return NULL;
}

void ko_free(SceUID handle)
{
    if (ko_get(handle))
    {
        kernelObjects.pool[handle - HANDLEOFFSET].occupied = 0;
        free(kernelObjects.pool[handle - HANDLEOFFSET].ptr);
        kernelObjects.pool[handle - HANDLEOFFSET].ptr = NULL;
    }
}

SceUID ko_init(void *obj, KoType type)
{
    s32 i;
    for (i = 0; i < MAXCOUNT; i++)
    {
        if (!kernelObjects.pool[i].occupied)
        {
            kernelObjects.pool[i].occupied = 1;
            kernelObjects.pool[i].ptr = obj;
            kernelObjects.pool[i].type = type;
            kernelObjects.pool[i].uid = i + HANDLEOFFSET;
            return kernelObjects.pool[i].uid;
        }
    }
    return 0;
}

void kop_clear()
{
    s32 i;
    for (i = 0; i < MAXCOUNT; i++)
    {
        if (kernelObjects.pool[i].occupied)
            free(kernelObjects.pool[i].ptr);
        kernelObjects.pool[i].occupied = 0;
    }
}

